﻿using FundHelper.Utility;
using MysToolCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static OfficeOpenXml.ExcelErrorValue;


namespace FundHelper.Model
{
    public static partial class Indicator
    {
        public static IEnumerable<BIASResult> GetBIASResult(this IEnumerable<(DateTime date, double price)> list, int period)
        {
            var tuples = list.ToList();
            if (tuples.Count <= period)
                throw new ArgumentException("无足够的数据计算BIAS");
            var his = tuples.OrderByDescending(a => a.date).ToArray();

            BIASResult[] biasArr = new BIASResult[his.Length - period];
            var temp = tuples.OrderBy(a => a.date).ToList();
            var range = new Range();
            for (int i = period; i < temp.Count; i++)
            {
                var date = temp[i].date;
                range = new Range(i - period + 1, i + 1);
                var prices = temp.Take(range).Select(a => a.price);
                var ma = prices.Average();
                var price = prices.Last();
                double bias = (double)(price-ma) / ma * 100f;
                biasArr[i - period] = new BIASResult(temp[i].date, bias)
                { Period = period };
            }
            return biasArr.Reverse();
        }
    }


    public class BIASResult(DateTime dateTime, double value) : IndicatorResult(dateTime, value)
    {
        public double Period { get; init; }
    }
    class BIASResultCollection:MultiPeriodCollection<BIASResult>
    {
        private BIASResultCollection() { }

        
        protected override LagCollection<BIASResult> CalPeriod(IEnumerable<ICanToTuple> his, int period)
        {
            var temp = his.ToQuote().ToArray();
            if (temp.Last().Date > temp.First().Date)
                temp = temp.OrderByDescending(a => a.Date).ToArray();

            BIASResult[] result = new BIASResult[temp.Length - period];
            //引入滑动窗口的概念。。从0开始，逐步往后，每次把前一个值移除，增加后一个值
            var span=temp.AsSpan();
            double sum = 0;
            double price = span[0].Price;
            for (int i=0; i<period; i++)
            {
                sum += span[i].Price;
            }
            for (int i = 0; i < result.Length; i++)
            {
                price = span[i].Price;
                //滑动窗口，先减去当前的值，再加上周期最后一个值
                var mean =sum/ period;
                double value = (double)(price - mean) / mean * 100f;
                result[i] = new BIASResult(span[i].Date, value);
                // 更新滑动窗口的和
                if (i + period < span.Length)
                {
                    sum = sum - price + span[i + period].Price;
                }
            }
            return new LagCollection<BIASResult>(result);
        }
    }

    class BIAS
    {
        public double BIAS5;
        public double BIAS10;
        public double BIAS20;
        public double MA5;
        public double MA10;
        public double MA20;
        public DateTime today;
        public double dwjz;
        public List<FundHistory> his;

        public BIAS(List<FundHistory> his, DateTime today, double? dwjz)
        {
            this.his = his.OrderByDescending(a => a.date).ToList();
            this.today = today;
            if (dwjz == null)
            {
                this.dwjz = his.First(a => a.date >= today).dwjz;
            }
            else
            {
                this.dwjz = dwjz.Value;
            }
        }

        public BIAS Process()
        {
            var oldFund = his.FindAll(a => a.date < today);
            MA5 = oldFund.Take(5).Average(a => a.dwjz);
            MA10 = oldFund.Take(10).Average(a => a.dwjz);
            MA20 = oldFund.Take(20).Average(a => a.dwjz);
            BIAS5 = (dwjz - MA5) / MA5 * 100;
            BIAS10 = (dwjz - MA10) / MA10 * 100;
            BIAS20 = (dwjz - MA20) / MA20 * 100;


            return this;
        }

        public BIAS Print()
        {
            MyConsole.Write($"MA5：{MA5.Str()}", ConsoleColor.Cyan);
            MyConsole.Write($" MA10：{MA10.Str()}", ConsoleColor.Cyan);
            MyConsole.WriteLine($" MA20：{MA20.Str()}", ConsoleColor.Cyan);
            MyConsole.Write($"BIAS5：{BIAS5.Str()}", BIAS5 > 0);
            MyConsole.Write($" BIAS10：{BIAS10.Str()}", BIAS10 > 0);
            MyConsole.WriteLine($" BIAS20：{BIAS20.Str()}", BIAS20 > 0);

            return this;
        }

        public static double MA(params double[] dwjz)
        {
            return dwjz.Average();
        }
    }
}
